package com.bingxue.edu.management.report.service;

import cn.hutool.core.util.StrUtil;
import com.bingxue.edu.common.enums.ClassCategoryEnum;
import com.bingxue.edu.common.enums.ClassStatusEnum;
import com.bingxue.edu.common.enums.EmployeeTypeEnum;
import com.bingxue.edu.framework.mybatis.base.BaseService;
import com.bingxue.edu.management.education.model.entity.Lesson;
import com.bingxue.edu.management.education.service.LessonService;
import com.bingxue.edu.management.education.service.LessonStudentService;
import com.bingxue.edu.management.report.mapper.MonthlyTeacherLessonMapper;
import com.bingxue.edu.management.report.model.entity.MonthlyTeacherLesson;
import com.bingxue.edu.management.report.model.query.MonthlyTeacherLessonQuery;
import com.bingxue.edu.management.report.model.resp.ClassLessonStat;
import com.bingxue.edu.management.report.model.resp.LessonSignInStat;
import com.bingxue.edu.management.report.model.resp.MonthlyTeacherLessonResp;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.bingxue.edu.management.education.model.entity.table.ClassInfoTableDef.CLASS_INFO;
import static com.bingxue.edu.management.education.model.entity.table.LessonTableDef.LESSON;
import static com.bingxue.edu.management.report.model.entity.table.MonthlyTeacherLessonTableDef.MONTHLY_TEACHER_LESSON;
import static com.bingxue.edu.management.system.model.entity.table.EmployeeTableDef.EMPLOYEE;

/**
 * 教师课时月报服务层
 */
@Service
@RequiredArgsConstructor
public class MonthlyTeacherLessonService extends BaseService<MonthlyTeacherLessonMapper, MonthlyTeacherLesson> {

    private final LessonService lessonService;
    private final LessonStudentService lessonStudentService;

    /**
     * 查询教师课时月报列表
     *
     * @param query 查询条件
     */
    public List<MonthlyTeacherLessonResp> getMonthlyTeacherLessonList(MonthlyTeacherLessonQuery query) {
//        YearMonth yearMonth = YearMonth.now();
        YearMonth yearMonth = query.getMonth();
        LocalDate firstDay = yearMonth.atDay(1);
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(MONTHLY_TEACHER_LESSON.ALL_COLUMNS,
                        CLASS_INFO.NAME.as(MonthlyTeacherLessonResp::getClassName),
                        EMPLOYEE.NAME.as(MonthlyTeacherLessonResp::getTeacherName))
                .from(MONTHLY_TEACHER_LESSON)
                .leftJoin(CLASS_INFO).on(CLASS_INFO.ID.eq(MONTHLY_TEACHER_LESSON.CLASS_ID))
                .leftJoin(EMPLOYEE).on(
                        EMPLOYEE.ID.eq(MONTHLY_TEACHER_LESSON.LEAD_TEACHER_ID, query.getTeacherType().equals(EmployeeTypeEnum.LEAD_TEACHER))
                                .and(EMPLOYEE.ID.eq(MONTHLY_TEACHER_LESSON.ASSIST_TEACHER_ID, query.getTeacherType().equals(EmployeeTypeEnum.ASSIST_TEACHER)))
                )
                .where(CLASS_INFO.SUBJECT.eq(query.getSubject()))
                    .and(CLASS_INFO.GRADE.eq(query.getGrade()))
                    .and(CLASS_INFO.TERM.eq(query.getTerm()))
                    .and(CLASS_INFO.CLASS_YEAR.eq(query.getClassYear()))
                    .and(MONTHLY_TEACHER_LESSON.LEAD_TEACHER_ID.isNotNull(query.getTeacherType().equals(EmployeeTypeEnum.LEAD_TEACHER)))
                    .and(MONTHLY_TEACHER_LESSON.ASSIST_TEACHER_ID.isNotNull(query.getTeacherType().equals(EmployeeTypeEnum.ASSIST_TEACHER)))
                    .and(MONTHLY_TEACHER_LESSON.REPORT_DATE.eq(firstDay))
                .orderBy(EMPLOYEE.NAME.asc());
        List<MonthlyTeacherLessonResp> resp = this.listAs(queryWrapper, MonthlyTeacherLessonResp.class);
        for (MonthlyTeacherLessonResp item : resp) {
            if (query.getTeacherType().equals(EmployeeTypeEnum.LEAD_TEACHER)) {
                item.setLessonPriceFactor(item.getLeadTeacherLessonPriceFactor());
            } else {
                item.setLessonPriceFactor(item.getAssistTeacherLessonPriceFactor());
            }
        }
        return resp;
    }

    /**
     * 计算课时月报
     * 高级班：权限等级≥600的小学思维课
     * 课时费计算规则：
     * 所有班级合并计算课时费系数X，普通班单独计算课时费系数Y。
     * 若X≥Y，则所有班级课时费系数都为X；否则，普通班课时费系数为Y，高级班课时费系数为1。
     */
    @Transactional(rollbackFor = Exception.class)
    public void computeTeacherLessonReport(YearMonth yearMonth) {
        LocalDate firstDay = yearMonth.atDay(1);
        LocalDate lastDay = yearMonth.atEndOfMonth();
        LocalDateTime now = LocalDateTime.now();
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(
                        LESSON.DEFAULT_COLUMNS,
                        CLASS_INFO.ID,
                        CLASS_INFO.LEAD_TEACHER_ID,
                        CLASS_INFO.ASSIST_TEACHER_ID,
                        CLASS_INFO.LESSON_HOUR_FACTOR,
                        CLASS_INFO.GRADE,
                        CLASS_INFO.SUBJECT,
                        CLASS_INFO.CLASS_LEVEL_LIMIT.as(ClassLessonStat::getClassLevel)
                ).from(LESSON)
                .leftJoin(CLASS_INFO).on(CLASS_INFO.ID.eq(LESSON.CLASS_ID))
                .where(LESSON.LESSON_DATE.between(firstDay, lastDay))
                    .and(CLASS_INFO.CLASS_CATEGORY.eq(ClassCategoryEnum.LONG_TERM_CLASS))
                    .and(CLASS_INFO.CLASS_STATUS.ne(ClassStatusEnum.CLOSED));
        List<ClassLessonStat> classLessonStats = lessonService.listAs(queryWrapper, ClassLessonStat.class);
        List<MonthlyTeacherLesson> monthlyTeacherLessonList = classLessonStats.stream().map(item -> convert(item, firstDay, now)).toList();

        computeLessonPriceFactor(monthlyTeacherLessonList, true);
        computeLessonPriceFactor(monthlyTeacherLessonList, false);
        this.updateMonthlyReport(firstDay, monthlyTeacherLessonList);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateMonthlyReport(LocalDate firstDay, List<MonthlyTeacherLesson> records) {
        this.updateChain()
                .where(MONTHLY_TEACHER_LESSON.REPORT_DATE.eq(firstDay))
                .remove();
        this.saveBatch(records);
    }

    /**
     * 计算主讲老师课时费系数
     */
    private void computeLessonPriceFactor(List<MonthlyTeacherLesson> monthlyTeacherLessonList, boolean isLeadTeacher) {
        Map<String, List<MonthlyTeacherLesson>> teacherLessonMap;
        if (isLeadTeacher) {
            teacherLessonMap = monthlyTeacherLessonList.stream()
                    .collect(Collectors.groupingBy(MonthlyTeacherLesson::getLeadTeacherId));
        } else {
            teacherLessonMap = monthlyTeacherLessonList.stream()
                    .filter(item -> StrUtil.isNotEmpty(item.getAssistTeacherId()))
                    .collect(Collectors.groupingBy(MonthlyTeacherLesson::getAssistTeacherId));
        }
        for (String teacherId : teacherLessonMap.keySet()) {
            List<MonthlyTeacherLesson> lessonList = teacherLessonMap.get(teacherId);
            // 所有班级、普通班、高级班的签到数量
            int allFullClassCount = 0, allSignInCount = 0;
            int normalFullClassCount = 0, normalSignInCount = 0;
            int vipFullClassCount = 0, vipSignInCount = 0;
            for (MonthlyTeacherLesson teacherLesson : lessonList) {
                allFullClassCount += teacherLesson.getFullClassCount();
                allSignInCount += teacherLesson.getSignInCount();
                if (isVipClass(teacherLesson.getClassLevel(), teacherLesson.getSubject())) {
                    vipFullClassCount += teacherLesson.getFullClassCount();
                    vipSignInCount += teacherLesson.getSignInCount();
                } else {
                    normalFullClassCount += teacherLesson.getFullClassCount();
                    normalSignInCount += teacherLesson.getSignInCount();
                }
            }
            double allFullRate = 0.0;
            double normalFullRate = 0.0;
            double vipFullRate = 0.0;
            if (allFullClassCount != 0) {
                allFullRate = (double) allSignInCount / allFullClassCount;
            }
            if (normalFullClassCount != 0) {
                normalFullRate = (double) normalSignInCount / normalFullClassCount;
            }
            if (vipFullClassCount != 0) {
                vipFullRate = (double) vipSignInCount / vipFullClassCount;
            }
            double allLessonPriceFactor = fullRateToLessonPriceFactor(allFullRate);
            double normalLessonPriceFactor = fullRateToLessonPriceFactor(normalFullRate);
            double vipLessonPriceFactor = fullRateToLessonPriceFactor(vipFullRate);
            // 如果全都是高端班，取max(1, vipLessonPriceFactor)
            if (normalFullClassCount == 0) {
                vipLessonPriceFactor = Math.max(1.0, vipLessonPriceFactor);
            } else if (allLessonPriceFactor >= normalLessonPriceFactor) {
                normalLessonPriceFactor = allLessonPriceFactor;
                vipLessonPriceFactor = allLessonPriceFactor;
            } else {
                vipLessonPriceFactor = Math.max(1.0, vipLessonPriceFactor);
            }
            for (MonthlyTeacherLesson teacherLesson : lessonList) {
                // 普通班
                if (isVipClass(teacherLesson.getClassLevel(), teacherLesson.getSubject())) {
                    if (isLeadTeacher) {
                        teacherLesson.setLeadTeacherLessonPriceFactor(vipLessonPriceFactor);
                    } else {
                        teacherLesson.setAssistTeacherLessonPriceFactor(vipLessonPriceFactor);
                    }
                } else {
                    if (isLeadTeacher) {
                        teacherLesson.setLeadTeacherLessonPriceFactor(normalLessonPriceFactor);
                    } else {
                        teacherLesson.setAssistTeacherLessonPriceFactor(normalLessonPriceFactor);
                    }
                }
            }
        }
    }

    private MonthlyTeacherLesson convert(ClassLessonStat classLessonStat, LocalDate firstDay, LocalDateTime now) {
        MonthlyTeacherLesson monthlyTeacherLesson = new MonthlyTeacherLesson();
        monthlyTeacherLesson.setReportDate(firstDay);
        monthlyTeacherLesson.setClassId(classLessonStat.getId());
        monthlyTeacherLesson.setLeadTeacherId(classLessonStat.getLeadTeacherId());
        monthlyTeacherLesson.setAssistTeacherId(classLessonStat.getAssistTeacherId());
        monthlyTeacherLesson.setLessonCount(classLessonStat.getLessonList().size());
        monthlyTeacherLesson.setLessonHourFactor(classLessonStat.getLessonHourFactor());
        monthlyTeacherLesson.setSubject(classLessonStat.getSubject());
        monthlyTeacherLesson.setClassLevel(classLessonStat.getClassLevel());
        monthlyTeacherLesson.setCreateTime(now);
        Map<String, Integer> lessonIndexMap = classLessonStat.getLessonList().stream().collect(Collectors.toMap(Lesson::getId, Lesson::getLessonIndex));
        // 查询课次签到详情
        List<LessonSignInStat> lessonSignInStatList = lessonStudentService.getLessonSignInStat(lessonIndexMap.keySet());
        lessonSignInStatList.sort(Comparator.comparingInt(a -> lessonIndexMap.get(a.getLessonId())));
        // signInDetails
        List<Integer> signDetails = lessonSignInStatList.stream().map(LessonSignInStat::getSignInCount).toList();
        monthlyTeacherLesson.setSignInDetails(signDetails);
        // totalSignInCount
        int totalSignInCount = lessonSignInStatList.stream().mapToInt(LessonSignInStat::getSignInCount).sum();
        monthlyTeacherLesson.setSignInCount(totalSignInCount);
        // fullClassCount
        int gradeLevel = Integer.parseInt(classLessonStat.getGrade().replace("grade", ""));
        int fullClassCount = classLessonStat.getLessonList().size() * 15;
        if(gradeLevel <= 2) {
            fullClassCount = classLessonStat.getLessonList().size() * 12;
        }
        monthlyTeacherLesson.setFullClassCount(fullClassCount);
//        monthlyTeacherLesson.setLeadTeacherLessonPriceFactor(1.0);

        return monthlyTeacherLesson;
    }

    private boolean isVipClass(Integer classLevel, String subject) {
        return classLevel >= 600 && subject.equals("math-xx");
    }

    private Double fullRateToLessonPriceFactor(Double fullRate) {
        if (fullRate >= 1.2) {
            return 1.15;
        } else if (fullRate >= 1.1) {
            return 1.1;
        } else if (fullRate >= 1.0) {
            return 1.05;
        } else if (fullRate >= 0.75) {
            return 1.0;
        } else if (fullRate >= 0.6) {
            return 0.9;
        } else if (fullRate >= 0.45) {
            return 0.7;
        } else {
            return 0.5;
        }
    }
}
